package com.zikao.user.controller;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.*;

import com.zikao.common.service.EmailService;
import com.zikao.common.service.RedisService;
import com.zikao.common.utils.MyMessage;
import com.zikao.common.utils.VerifyCode;
import com.zikao.common.vo.TableListVo;
import com.zikao.user.utils.GenerateActivatedLinkUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import com.zikao.user.entity.UserEntity;
import com.zikao.user.service.UserService;
import com.zikao.common.utils.PageUtils;
import com.zikao.common.utils.R;

import javax.imageio.ImageIO;
import javax.mail.MessagingException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author likaisheng
 * @email 1805318928@qq.com
 * @date 2021-02-21 11:10:21
 */

@Controller
@RequestMapping("user/user")
@Slf4j
public class UserController {
    @Autowired
    private UserService userService;
    @Autowired
    private RedisService redisService;

    @RequestMapping("/manage/setAdmin/{id}")
    @ResponseBody
    public R setAdmin(@PathVariable("id") Long id){
        UserEntity user = new UserEntity();
        user.setId(id);
        user.setIsAdmin(1);
        userService.updateById(user);
        return R.ok();
    }

    @RequestMapping("/manage/cancelAdmin/{id}")
    @ResponseBody
    public R cancelAdmin(@PathVariable("id") Long id){
        UserEntity user = new UserEntity();
        user.setId(id);
        user.setIsAdmin(0);
        userService.updateById(user);
        return R.ok();
    }

    @RequestMapping("/listForLayUI")
    @ResponseBody
    public TableListVo listForLayUI(@RequestParam Map<String, Object> params){
        List<UserEntity> userList = userService.selectByMap(new HashMap<>());

        TableListVo<UserEntity> tableListVo = new TableListVo();
        tableListVo.setCode(0);
        tableListVo.setMsg("");
        tableListVo.setCount(userList.size());

        tableListVo.setData(userList);
        return tableListVo;
    }

    @RequestMapping("/delMessage")
    @ResponseBody
    public R delMessage(@RequestBody Map<String, Object> params){
        String email = (String) params.get("email");
        String uuid = (String) params.get("uuid");
        List<MyMessage> messges = redisService.getMessges(email);
        for (MyMessage message : messges){
            if (message.getUuid().equals(uuid)){
                redisService.delMessage(email,message);
                return R.ok();
            }
        }
        return R.error();
    }
    /**
     * 获取用户的未读消息列表
     * @return
     */
    @RequestMapping("/messageList/{email}")
    @ResponseBody
    public List<MyMessage> messageList(@PathVariable("email") String email){
        List<MyMessage> messges = redisService.getMessges(email);
        return messges;
    }

    // 此处的id，不是用户id，这个id是用来处理树型导航的
    @RequestMapping("/toUserCenter/{id}")
    public String toUserCenter(@PathVariable("id") Long id, Model model,HttpServletRequest request,HttpServletResponse response){
        UserEntity user = (UserEntity) request.getSession().getAttribute("user");
        model.addAttribute("nav-item",id);
        model.addAttribute("user",user);
        return "userCenter";
    }

    /* 获取验证码图片*/
    @RequestMapping("/getVerifyCode")
    @ResponseBody
    public void getVerificationCode(HttpServletRequest request,HttpServletResponse response) {
        try {
            int width = 200;
            int height = 69;
            BufferedImage verifyImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            // 生成对应宽高的初始图片
            String randomText = VerifyCode.drawRandomText(width, height, verifyImg);
            // 单独的一个类方法，出于代码复用考虑，进行了封装。
            // 功能是生成验证码字符并加上噪点，干扰线，返回值为验证码字符
            request.getSession().setAttribute("verifyCode", randomText);
            System.out.println(request.getSession());
            response.setContentType("image/png");//必须设置响应内容类型为图片，否则前台不识别
            OutputStream os = response.getOutputStream(); //获取文件输出流
            ImageIO.write(verifyImg, "png", os);//输出图片流
            os.flush();
            os.close();//关闭流
        } catch (IOException e) {
            log.error(e.getMessage());
            e.printStackTrace();
        }
    }

    /* 用户激活*/
    @RequestMapping("/activate")
    @ResponseBody
    public String activate(Long id,String checkCode) {
        try{
            UserEntity user = userService.getById(id);
            boolean res = GenerateActivatedLinkUtils.verifyCheckcode(user, checkCode);
            if (res){
                user.setIsActivated(1);
                userService.updateById(user);
            }else{
                return "激活失败";
            }
        }catch (Exception e){
            log.error("激活失败：",e);
            return "激活失败";
        }
        return "激活成功";
    }

    /**
     * 注销
     * @param model
     * @return
     */
    @GetMapping("/logout")
    public String logout(Model model){
        Subject currentUser = SecurityUtils.getSubject();
        if (currentUser.isAuthenticated()){
            currentUser.logout();
        }
        return "redirect:/index";
    }

    /**
     * 登录 - Shiro写法
     */
    @RequestMapping("/login")
    @ResponseBody
    public R login(@RequestBody UserEntity user,HttpServletRequest request,HttpServletResponse response) {
        // 判断验证码
        String verifyCode = (String) request.getSession().getAttribute("verifyCode");
        if (!Optional.ofNullable(verifyCode).orElse("").equalsIgnoreCase(user.getVerifyCode())){
            return R.error("验证码错误");
        }

        // Shiro认证写法
        Subject currentUser = SecurityUtils.getSubject();
        if (!currentUser.isAuthenticated()){
            // 把用户名和密码封装为UsernamePasswordToken
            UsernamePasswordToken token = new UsernamePasswordToken(user.getEmail(),user.getPwd());
            token.setRememberMe(true);

            try {
                // 执行登录
                currentUser.login(token);
            }catch (AccountException e){
                log.error("程序发生AccountException",e);
                return R.error(e.getMessage());
            }catch (Exception e){
                log.error("程序发生错误-login",e);
                return R.error("登录失败，发生未知错误");
            }
        }

        // 登录成功，将user放入session中，方便系统获取用户信息
        Map<String,Object> userMap = new HashMap<>();
        userMap.put("email",user.getEmail());
        List<UserEntity> userList = userService.selectByMap(userMap);
        UserEntity dbUser = userList.get(0);
        // 抹去部分信息，以保证安全
        UserEntity userEntity = new UserEntity();
        userEntity.setName(dbUser.getName());
        userEntity.setId(dbUser.getId());
        userEntity.setEmail(dbUser.getEmail());
        userEntity.setGender(dbUser.getGender());
        userEntity.setAge(dbUser.getAge());
        userEntity.setProfileUrl(dbUser.getProfileUrl());
        userEntity.setAddress(dbUser.getAddress());
        request.getSession().setAttribute("user",userEntity);

        // 登录成功，在redis中获取未读信息，存入session中
        List<MyMessage> messges = redisService.getMessges(user.getEmail());
        if (messges.size() > 0){
            request.getSession().setAttribute("messageRemind",messges.size());
        }
        return R.ok("登录成功");
    }

    /**
     * 列表
     */
    @RequestMapping("/list")
    @ResponseBody
    public R list(@RequestParam Map<String, Object> params) {
        PageUtils page = userService.queryPage(params);

        return R.ok().put("page", page);
    }


    /**
     * 信息
     */
    @RequestMapping("/info/{id}")
    @ResponseBody
    public R info(@PathVariable("id") Long id) {
        UserEntity user = userService.getById(id);

        return R.ok().put("user", user);
    }

    /**
     * 检查邮箱是否已注册
     */
    @RequestMapping("/checkEmail")
    @ResponseBody
    public R checkEmail(String email) {
        try{
            Map<String,Object> userMap = new HashMap<>();
            userMap.put("email",email);
            List<UserEntity> userList = userService.selectByMap(userMap);
            if (userList.size() == 0){
                return R.ok("可以使用");
            }else{
                return R.error("邮箱已注册，不能再注册");
            }
        }catch (Exception e){
            log.error("检查邮箱是否已注册出现错误：",e);
            return R.error();
        }
    }
    /**
     * 检查用户名
     */
    @RequestMapping("/checkName")
    @ResponseBody
    public R checkName(String name) {
        try{
            Map<String,Object> userMap = new HashMap<>();
            userMap.put("name",name);
            List<UserEntity> userList = userService.selectByMap(userMap);
            if (userList.size() == 0){
                return R.ok("可以使用");
            }else{
                return R.error("用户名重复，不能使用");
            }
        }catch (Exception e){
            log.error("检查用户名出现错误：",e);
            return R.error();
        }
    }

    /**
     * 注册
     */
    @RequestMapping("/regist")
    @ResponseBody
    public R regist(@RequestBody UserEntity user) {
        try{
            // 注册
            user.setUuid(UUID.randomUUID().toString());
            user.setIsActivated(0);
            user.setIsAdmin(0);
            // 密码采用MD5盐值加密
            ByteSource salt = ByteSource.Util.bytes(user.getEmail());
            SimpleHash pwdHsah = new SimpleHash("MD5", user.getPwd(), salt, 4);
            user.setPwd(pwdHsah.toString());
            userService.save(user);

            // 发送激活邮件
            String activatedLinkStr = GenerateActivatedLinkUtils.generateActivatedLink(user);

            EmailService emailService = new EmailService() {
                @Override
                public void createMimeMessage(MimeMessage message) throws UnsupportedEncodingException, MessagingException {
                    message.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(user.getEmail(), user.getName()+"先生", "UTF-8"));
                    message.setSubject("用户激活", "UTF-8");
                    message.setContent(activatedLinkStr, "text/html;charset=UTF-8");
                    message.setSentDate(new Date());
                    message.saveChanges();
                }
            };
            emailService.sendMail();
        }catch (Exception e){
            log.error("注册出现错误：",e);
            return R.error();
        }
        return R.ok("激活邮件已发送"+user.getEmail()+",请点击邮件进行激活,激活后才能登录");
    }

    /**
     * 修改
     */
    @RequestMapping("/update")
    @ResponseBody
    public R update(@RequestBody UserEntity user) {
        userService.updateById(user);

        return R.ok();
    }

    /**
     * 删除
     */
    @RequestMapping("/delete")
    @ResponseBody
    public R delete(@RequestBody Long[] ids) {
        userService.removeByIds(Arrays.asList(ids));

        return R.ok();
    }
}
